#ifndef _RFC1813_H
#define _RFC1813_H

#include <array>
#include <string>
#include <vector>

using std::tr1::array;
using std::string;
using std::vector;

///////////////////////////////////////////////////////////////////////////////
// RFC 1813
// NFS v3

const ULONG NFS_PROGRAM = 100003;
const ULONG NFS_V3 = 3;

const ULONG NFS3_FHSIZE = 64; // The maximum size in bytes of the opaque file handle.
const ULONG NFS3_COOKIEVERFSIZE = 8; // The size in bytes of the opaque cookie verifier passed by READDIR and READDIRPLUS.
const ULONG NFS3_CREATEVERFSIZE = 8; //The size in bytes of the opaque verifier used for exclusive CREATE.
const ULONG NFS3_WRITEVERFSIZE = 8; // The size in bytes of the opaque verifier used for asynchronous WRITE.

typedef UINT32 uint32;
typedef UINT64 uint64;
typedef INT32 int32;
typedef INT64 int64;
typedef string filename3;
typedef string nfspath3;
typedef uint64 fileid3;
typedef uint64 cookie3;
typedef array<char, NFS3_COOKIEVERFSIZE> cookieverf3;
typedef array<char, NFS3_WRITEVERFSIZE> createverf3;
typedef array<char, NFS3_WRITEVERFSIZE> writeverf3;
typedef uint32 uid3;
typedef uint32 gid3;
typedef uint64 size3;
typedef uint64 offset3;
typedef uint32 mode3;
typedef uint32 count3;

enum nfsstat3 
{
  NFS3_OK             = 0,
  NFS3ERR_PERM        = 1,
  NFS3ERR_NOENT       = 2,
  NFS3ERR_IO          = 5,
  NFS3ERR_NXIO        = 6,
  NFS3ERR_ACCES       = 13,
  NFS3ERR_EXIST       = 17,
  NFS3ERR_XDEV        = 18,
  NFS3ERR_NODEV       = 19,
  NFS3ERR_NOTDIR      = 20,
  NFS3ERR_ISDIR       = 21,
  NFS3ERR_INVAL       = 22,
  NFS3ERR_FBIG        = 27,
  NFS3ERR_NOSPC       = 28,
  NFS3ERR_ROFS        = 30,
  NFS3ERR_MLINK       = 31,
  NFS3ERR_NAMETOOLONG = 63,
  NFS3ERR_NOTEMPTY    = 66,
  NFS3ERR_DQUOT       = 69,
  NFS3ERR_STALE       = 70,
  NFS3ERR_REMOTE      = 71,
  NFS3ERR_BADHANDLE   = 10001,
  NFS3ERR_NOT_SYNC    = 10002,
  NFS3ERR_BAD_COOKIE  = 10003,
  NFS3ERR_NOTSUPP     = 10004,
  NFS3ERR_TOOSMALL    = 10005,
  NFS3ERR_SERVERFAULT = 10006,
  NFS3ERR_BADTYPE     = 10007,
  NFS3ERR_JUKEBOX     = 10008
};

enum ftype3 
{
  NF3REG    = 1,
  NF3DIR    = 2,
  NF3BLK    = 3,
  NF3CHR    = 4,
  NF3LNK    = 5,
  NF3SOCK   = 6,
  NF3FIFO   = 7
};
typedef uint32 ftype3_int; // map ftype3 to integer type to make easier read/write operations.

struct specdata3 
{
  uint32     specdata1;
  uint32     specdata2;
};

struct nfs_fh3
{
  array<char, NFS3_FHSIZE> data;
};

struct nfstime3 
{
  uint32   seconds;
  uint32   nseconds;
};

struct fattr3 
{
  ftype3_int type; //ftype3
  mode3      mode;
  uint32     nlink;
  uid3       uid;
  gid3       gid;
  size3      size;
  size3      used;
  specdata3  rdev;
  uint64     fsid;
  fileid3    fileid;
  nfstime3   atime;
  nfstime3   mtime;
  nfstime3   ctime;
};

struct post_op_attr //switch (bool attributes_follow) 
{
  bool attributes_follow;
  //case TRUE:
  fattr3   attributes;
  //case FALSE:
  //void;
};

enum NfsV3Proc
{
  NFSPROC3_NULL = 0,
  NFSPROC3_GETATTR = 1,
  NFSPROC3_ACCESS = 4,
  NFSPROC3_FSINFO = 19,
  NFSPROC3_PATHCONF = 20
};

//-----------------------------------------------------------------------------
// NFSPROC3_ACCESS
const uint32 ACCESS3_READ    = 0x0001;
const uint32 ACCESS3_LOOKUP  = 0x0002;
const uint32 ACCESS3_MODIFY  = 0x0004;
const uint32 ACCESS3_EXTEND  = 0x0008;
const uint32 ACCESS3_DELETE  = 0x0010;
const uint32 ACCESS3_EXECUTE = 0x0020;

struct ACCESS3args 
{
  nfs_fh3  object;
  uint32   access;
};

struct ACCESS3resok 
{
  post_op_attr   obj_attributes;
  uint32         access;
};

struct ACCESS3resfail 
{
  post_op_attr   obj_attributes;
};

struct ACCESS3res
{
  nfsstat3 status;
  ACCESS3resok   resok;
  ACCESS3resfail resfail;
};

//-----------------------------------------------------------------------------
// NFSPROC3_FSINFO

const ULONG FSF3_LINK        = 0x0001;
const ULONG FSF3_SYMLINK     = 0x0002;
const ULONG FSF3_HOMOGENEOUS = 0x0008;
const ULONG FSF3_CANSETTIME  = 0x0010;

struct FSINFO3args 
{
  nfs_fh3 fsroot;
};

struct FSINFO3resok 
{
  post_op_attr obj_attributes;
  uint32       rtmax;
  uint32       rtpref;
  uint32       rtmult;
  uint32       wtmax;
  uint32       wtpref;
  uint32       wtmult;
  uint32       dtpref;
  size3        maxfilesize;
  nfstime3     time_delta;
  uint32       properties;
};

struct FSINFO3resfail 
{
  post_op_attr obj_attributes;
};

struct FSINFO3res //switch (nfsstat3 status) 
{
  nfsstat3 status;
  //case NFS3_OK:
  FSINFO3resok   resok;
  //default:
  FSINFO3resfail resfail;
};

//-----------------------------------------------------------------------------
// NFSPROC3_GETATTR

struct GETATTR3args 
{
  nfs_fh3   object;
};

struct GETATTR3resok 
{
  fattr3   obj_attributes;
};

struct GETATTR3res
{
  nfsstat3 status;
  GETATTR3resok  resok;
};

//-----------------------------------------------------------------------------
// NFSPROC3_PATHCONF

struct PATHCONF3args 
{
  nfs_fh3   object;
};

struct PATHCONF3resok 
{
  post_op_attr obj_attributes;
  uint32       linkmax;
  uint32       name_max;
  bool         no_trunc;
  bool         chown_restricted;
  bool         case_insensitive;
  bool         case_preserving;
};

struct PATHCONF3resfail 
{
  post_op_attr obj_attributes;
};

struct PATHCONF3res //switch (nfsstat3 status) 
{
  nfsstat3 status;
  //case NFS3_OK:
  PATHCONF3resok   resok;
  //default:
  PATHCONF3resfail resfail;
};

///////////////////////////////////////////////////////////////////////////////
// RFC 1813
// Mount v3

const ULONG MOUNT_PROGRAM = 100005;
const ULONG MOUNT_V3 = 3;

const ULONG MNTPATHLEN = 1024;  /* Maximum bytes in a path name */
const ULONG MNTNAMLEN  = 255;   /* Maximum bytes in a name */
const ULONG FHSIZE3    = 64;    /* Maximum bytes in a V3 file handle */

typedef array<char, FHSIZE3> fhandle3;
typedef array<char, MNTPATHLEN> dirpath;
typedef array<char, MNTNAMLEN> name;

enum mountstat3 
{
  MNT3_OK = 0,                 /* no error */
  MNT3ERR_PERM = 1,            /* Not owner */
  MNT3ERR_NOENT = 2,           /* No such file or directory */
  MNT3ERR_IO = 5,              /* I/O error */
  MNT3ERR_ACCES = 13,          /* Permission denied */
  MNT3ERR_NOTDIR = 20,         /* Not a directory */
  MNT3ERR_INVAL = 22,          /* Invalid argument */
  MNT3ERR_NAMETOOLONG = 63,    /* Filename too long */
  MNT3ERR_NOTSUPP = 10004,     /* Operation not supported */
  MNT3ERR_SERVERFAULT = 10006  /* A failure on the server */
};

enum MountV3Proc
{
  MOUNTPROC3_NULL = 0,
  MOUNTPROC3_MNT = 1,
  MOUNTPROC3_UMNT = 3
};

//-----------------------------------------------------------------------------
// MOUNTPROC3_MNT

struct mountres3_ok 
{
  fhandle3   fhandle;
  vector<int> auth_flavors;
};

struct mountres3 //switch (mountstat3 fhs_status) 
{
  mountstat3 fhs_status;
  //case MNT_OK:
  mountres3_ok  mountinfo;
  //default:
  //void;
};

///////////////////////////////////////////////////////////////////////////////

#endif //_RFC1813_H